
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Diagnostics;
using System.Xml;
using System.Reflection;
using System.Collections;
using Swaf.Container;

namespace Swaf.Call
{
	/// <summary>
	/// Exposes the ability to call a web service from a rule or task
	/// </summary>
	public class WebServiceCall : BaseCall
	{
		/// <summary>
		/// The call instance
		/// </summary>
		protected DynamicWebServiceCall m_call;
		private static IMap m_map = new FlexiMap();
		private static String m_timeOut = "expire in 1 day";

		/// <summary>
		/// Constructor with name and initialization information
		/// </summary>
		public WebServiceCall(string name, XmlElement initInfo)
			:base(name, initInfo)
		{
			XmlElement constructorParams = (XmlElement) initInfo.SelectSingleNode("ConstructorParams");
			
			try
			{
				// Process the call
				ProcessCall(m_className, m_methodName, constructorParams);
			}
			catch(Exception e)
			{
				throw new CallException(String.Format("Unable to create instance of class: {0}", m_className), e);
			}
		}

		/// <summary>
		/// Constructor with this instance, method to be called, and params
		/// </summary>
		public WebServiceCall(object onThis, string method, params object[] p)
			:base("", method, p)
		{
			Debug.Assert(onThis != null);
			m_className = onThis.GetType().FullName;

			// Process the call
			ProcessCall(m_className, method, null);
		}

		/// <summary>
		/// Invoke the method with the supplied params
		/// </summary>
		public override object call(params object[] p)
		{
			Debug.Assert(m_call != null, "m_call should never be null");
			return m_call.call(this.calcCallParams(MassageParams(p)));
		}

		/// <summary>
		/// Process the request and invoke the call for the supplied class and method combination
		/// </summary>
		private void ProcessCall(String className, String methodName, XmlElement constructorParams)
		{
			// Build a key for the call
			String key = className + ":" + methodName;
					
			// Get the stashed call if it exists
			m_call = m_map.get(key) as DynamicWebServiceCall; 
			
			// If the call is null create a new one.  Otherwise, use the one from the map.
			if (m_call == null)
			{
				// Were any params passed
				if (constructorParams!= null)
				{
					m_call = new DynamicWebServiceCall(m_className, m_methodName, constructorParams.SelectNodes("Param"));
				}
				else
				{ 
					m_call = new DynamicWebServiceCall(className, methodName);
				}

				// Stash the call reference
				m_map.put(key, m_call, m_timeOut);
			}
		}
		
		/// <summary>
		/// Remove the application and rule context
		/// </summary>
		private Object[] MassageParams(params object[] p)
		{
			ArrayList arr = new ArrayList();
			// Enumerate thru the params and remove IApplication and IRuleContext
			for (Int32 i = 0; i < p.Length; i++)
			{
				if (p[i] is Swaf.IApplication  || p[i] is Swaf.BizRule.IRuleContext){}
				else
				{
					arr.Add(p[i]);
				}
			}

			Object[] outParams = new object[arr.Count];
			// Enumerate thru the params that should be returned after the IApplication and IRuleContext 
			// have been removed
			for (Int32 i = 0; i < arr.Count; i++)
			{
				outParams[i] = arr[i];
			}

			return outParams;
		}
	}
}
